/*
 * Copyright (c) 2009. Silenus Consultoria, S.L.
 */
package es.silenus.detecta.dao.impl;

import es.silenus.detecta.dao.OrganizationDAO;

import es.silenus.detecta.model.Organization;

import org.hibernate.FetchMode;
import org.hibernate.Session;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;


/**
 * Organization DAO implementation.
 *
 * @author <a href="mailto:malonso@silenus-consultoria.es">Mariano Alonso</a>
 *
 * @since 31-mar-2009 13:02:27
 */
public class OrganizationDAOImpl extends ReadWriteDAOImpl<Organization, Integer> implements OrganizationDAO {
	/**
	 * Find an organization by its name
	 *
	 * @param name the name
	 *
	 * @return the located organization or, if not found, null
	 */
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public Organization findByName(String name) {
		Session session = null;

		try {
			session = getSession();

			return (Organization)session.getNamedQuery(Organization.class.getName() + ".findByName").setString("name", name)
																	.uniqueResult();
		} finally {
			releaseSession(session);
		}
	}

	/**
	 * Retrieve the names.
	 *
	 * @return the organization names sorted alphabetically.
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public List<String> findNames() {
		return getHibernateTemplate().findByNamedQuery(Organization.class.getName() + ".findAllGroups");
	}

	/**
	 * Retrieve the user login names, given an organization name.
	 *
	 * @param name the name.
	 *
	 * @return the user logins.
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public List<String> findUserLogins(final String name) {
		return getHibernateTemplate()
						 .findByNamedQueryAndNamedParam(Organization.class.getName() + ".findLogins", "name", name);
	}

	/**
	 * Loads every single instance of a persistent class.
	 *
	 * @return list of instances.
	 */
	@Override
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public List<Organization> findAll() {
		Session session = null;

		try {
			session = getSession();

			return session.getNamedQuery(Organization.class.getName() + ".findAll")
										.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY).list();
		} finally {
			releaseSession(session);
		}
	}

	/**
	 * Builds a page. Override this to provide a custom behaviour.
	 *
	 * @return a page.
	 */
	@Override
	public PageImpl<Organization> buildPage() {
		PageImpl<Organization> page = new PageImpl<Organization>(getSessionFactory());

		page.setProjectionHack(true);

		return page;
	}

	/**
	 * Override this method to provide a find by example page criteria.
	 *
	 * @param criteria the criteria.
	 * @param object the sample object.
	 *
	 * @return the criteria.
	 */
	protected DetachedCriteria preparePageCriteria(final DetachedCriteria criteria, final Map<String, Object> object) {
		// To avoid duplicates see: http://jira.springframework.org/browse/SPR-5007
		// http://www.hibernate.org/117.html#A12
		criteria.setFetchMode("provinces", FetchMode.JOIN).setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);

		Object temp = object.get("id");

		if(temp != null) {
			criteria.add(Restrictions.eq("id", temp));
		}

		temp = object.get("name");

		if(temp != null) {
			criteria.add(Restrictions.ilike("name", (String)temp, MatchMode.ANYWHERE));
		}

		temp = object.get("provinces");

		if(temp != null) {
			criteria.createCriteria("provinces").add(Restrictions.in("id", (Object[])temp));
		}


		return criteria;
	}

	/**
	 * Override this method to provide a find by example list criteria.
	 *
	 * @param criteria the criteria.
	 * @param object the sample object.
	 *
	 * @return the criteria.
	 */
	protected DetachedCriteria prepareListCriteria(final DetachedCriteria criteria, final Map<String, Object> object) {
		return preparePageCriteria(criteria, object);
	}
}
